iT邦幫忙

0

使用 C# 屬性增強工廠模式

c#
  • 分享至 

  • xImage
  •  
  1. 定義了兩個列舉:Platform 和 OutputFormat。
public enum Platform
{
    MacOS, Windows, Linux,
}

public enum OutputFormat
{
    AAC, Opus
}

2.定義了一個 EncoderFrontendAttribute 類別。這個類別繼承自 Attribute 類別,代表它是一個自訂屬性。

這個類別表示一個轉碼前端,提供了一個建構函式來指定它的名稱、輸出格式、以及支援的平台。

public class EncoderFrontendAttribute : Attribute
{
    public string Name;
    public OutputFormat OutputFormat;
    public Platform[] SupportedPlatforms;

    public EncoderFrontendAttribute(string name, OutputFormat outputFormat, params Platform[] supportedPlatforms)
    {
        Name = name;
        OutputFormat = outputFormat;
        SupportedPlatforms = supportedPlatforms;
    }
}
  1. 定義一個 IEncoder 介面
    表示所有轉碼器都必須實作的功能,包括獲取轉碼器的執行檔名稱、檢查轉碼器是否存在、設定轉碼器的參數,以及設定轉碼工作。
public interface IEncoder
{
    public string ExecutableName { get; }
    public bool WritesOutputToStdErr { get; }

    bool EnsureEncoderExists();
    IArgumentBuilder Configure();
    virtual TranscodingJob ConfigureTranscodingJob(TranscodingJobRequest request);
}

5.定義了一個 Qaac 類別,該類別提供了轉碼器的執行檔名稱、檢查轉碼器是否存在、以及設定轉碼器的參數的功能。
使用自訂屬性 EncoderFrontend 來標註這個類別。這個類別實作了 IEncoder 介面,表示它是一個轉碼器。

[EncoderFrontend(nameof(Qaac), OutputFormat.AAC, Platform.Windows)]
public class Qaac : IEncoder
{
    public string ExecutableName => "qaac";

    public bool WritesOutputToStdErr => true;

    public bool EnsureEncoderExists()
    {
        return CommonEncoderMethods.CheckEncoderExists(ExecutableName);
    }

    public IArgumentBuilder Configure()
    {
        return new QaacBuilder();
    }
}

總結一下,到目前為止,您已經建立了一個轉碼器必須實作的共同介面,以及一個自訂屬性,用於描述提供適當轉碼器所需的資料。

6.建立工廠
定義了一個名為 IEncoderFactory 的介面,以及一個名為 EncoderFactory 的類別,並且讓這個類別實作了 IEncoderFactory 介面。

這個工廠提供了兩個功能:獲取當前運行的平台,以及獲取指定格式的轉碼器。

public interface IEncoderFactory
{
    public Platform GetPlatform();
    public IEncoder? GetEncoder(OutputFormat format);
}

public class EncoderFactory : IEncoderFactory
{
    // it must be overrideable so it can be mocked
    public virtual Platform GetPlatform()
    {
        if (OperatingSystem.IsMacOS())
        {
            return Platform.MacOS;
        }

        if (OperatingSystem.IsLinux())
        {
            return Platform.Linux;
        }

        if (OperatingSystem.IsWindows())
        {
            return Platform.Windows;
        }

        throw new PlatformNotSupportedException("Only Windows, Linux and macOS are currently supported platforms.");
    }

    public IEncoder? GetEncoder(OutputFormat format)
    {
        var assemblies = typeof(IEncoder).Assembly;
        var encoders = assemblies
            .GetTypes()
            // get IEncoder classes
            .Where(x => x.GetInterface(nameof(IEncoder)) != null);

        foreach (var type in encoders)
        {
            var attribute = (EncoderFrontendAttribute)Attribute
                .GetCustomAttribute(type, typeof(EncoderFrontendAttribute))!;
            if (attribute.OutputFormat == format && attribute.SupportedPlatforms.Any(p => p == GetPlatform()))
            {
                return Activator.CreateInstance(type) as IEncoder;
            }
        }

        return null;
    }
}

這個工廠先使用反射獲取所有實作了 IEncoder 介面的類別,然後對這些類別迭代,並使用反射獲取它們附加的自訂屬性。最後,如果自訂屬性符合我們期望的輸出格式,並在當前的平台上運行,就返回一個轉碼器的新實例。

使用這個工廠的簡單寫法:

var encoder = _encoderFactory.GetEncoder(OutputFormat.AAC);

8.測試這個工廠

為了確保工廠的正常運行,我們使用模擬庫 NSubstitute 來寫測試,讓您在不修改類別功能的前提下模擬類別的一部分。

我們寫兩個測試方法:

  • GetEncoder_AACOnMacOS_ReturnsFFMPEG : 用於確保在 macOS 平台上獲取的轉碼器是預期的轉碼器。
  • GetEncoder_AACOnWindows_ReturnsQaac : 用於確保在 Windows 平台上獲取的轉碼器是預期的轉碼器。

這些測試方法可以確保在不同的平台上,能夠獲取預期的轉碼器。

public class EncoderFactoryTests
{
    private readonly IEncoderFactory _encoderFactory;

    public EncoderFactoryTests()
    {
        _encoderFactory = Substitute.ForPartsOf<EncoderFactory>();
    }

    [Fact]
    public void GetEncoder_AACOnMacOS_ReturnsFFMPEG()
    {
        // arrange
        _encoderFactory.Configure().GetPlatform().Returns(Platform.MacOS);

        // act
        var encoder = _encoderFactory.GetEncoder(OutputFormat.AAC);

        // assert
        Assert.NotNull(encoder);
        var encoderType = encoder.GetType();
        Assert.Equal(nameof(FfmpegForMacOS), encoderType.Name);
    }

    [Fact]
    public void GetEncoder_AACOnWindows_ReturnsQaac()
    {
        // arrange
        _encoderFactory.Configure().GetPlatform().Returns(Platform.Windows);

        // act
        var encoder = _encoderFactory.GetEncoder(OutputFormat.AAC);

        // assert
        Assert.NotNull(encoder);
        var encoderType = encoder.GetType()!;
        Assert.Equal(nameof(Qaac), encoderType.Name);
    }
}

使用 NSubstitute 模擬了 EncoderFactory 類別的 GetPlatform 方法,以確保它返回預期的平台。接著,它們呼叫 GetEncoder 方法並斷言返回的轉碼器的類型是預期的類型。


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言